/*Includes*/

#include "superblock.h"
#include "inode.h"
#include "global.h"
#include "directoryentry.h"

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<time.h>
#include<fcntl.h>

/*Function Declarations.*/

int EmptyTheBlocks(unsigned long);
int CreateRootDirectory(struct inode, unsigned long);
int InitializeSuperBlock(unsigned long);

/*Initialize the File System.*/

int FileSystemInitialization(unsigned long totalfsblocks, unsigned long inodeblocks)
{
numofdatablocksrem=totalfsblocks-inodeblocks-2;                   /*Blocks to store the contents of the file. Block 0 for Boot Strap and Block 1 for Superblock*/
numberofinodesrem=inodeblocks*16;
struct inode inode;

if (totalfsblocks<inodeblocks)
	{
		printf("Arguements invalid; Total blocks cannot be less than inode blocks\n");
		exit(1);
	}
/*To open the FS file*/
if((fsfd=open("ffs", O_CREAT|O_RDWR|O_TRUNC, 0664))<0)
	{
		printf("ERROR in init: fsfd<0 fsfd value=%d\n", fsfd);
		exit(1);
	}

/*Empty all the blocks of the File System*/

EmptyTheBlocks(totalfsblocks);

/*Create and Write to Super Block*/

InitializeSuperBlock(inodeblocks);

/*Create root directory*/

CreateRootDirectory(inode, inodeblocks);

}

int EmptyTheBlocks(unsigned long totalfsblocks)
{
int i, byteswritten;
char emptycontent[BLOCK_SIZE];

for(i=0;i<BLOCK_SIZE;i++)
	{	
		emptycontent[i]=0;
	}

for(i=0;i<totalfsblocks;i++)
	{
		byteswritten=write(fsfd, emptycontent, BLOCK_SIZE);
		if (byteswritten!=BLOCK_SIZE)
			printf("ERROR: Unable to empty the FS blocks\n");
	}

return 1;
}

int InitializeSuperBlock(unsigned long inodeblocks)
{
int i, rvalue;
time_t presenttime;
struct tm *currenttime;
presenttime=time(0);                               /*This gives current time in secs*/
currenttime=localtime(&presenttime);               /*This converts secs into hrs and mins and returns a pointer to a 'struct tm'*/

memset(&superblock, 0, sizeof(struct superblock));
superblock.isize=inodeblocks;
superblock.fsize=0;
superblock.nfree=100;
if (numofdatablocksrem >= 100)
	{
		for(i=0;i<100;i++)
		{
			superblock.free[i]=i;     /*The first block is for the root directory. Block address is (2+inodeblocks)*BLOCK_SIZE*/
		}
	}
else
	{
		for(i=0;i<numofdatablocksrem;i++)
		{
			superblock.free[i]=i;
		}
	    superblock.nfree=numofdatablocksrem;	
	}	
superblock.ninode=100;

if((inodeblocks*16)>100)
	{
	 for(i=0;i<100;i++)
		{
			superblock.inode[i]=i;  /*First inode (superblock.inode[0]) is for the root directory.*/
		}
	}
	else
	{
	 for(i=0;i<(inodeblocks*16);i++)
		{
			superblock.inode[i]=i;
		}
	 superblock.ninode=inodeblocks*16;	
	}
superblock.flock=0;
superblock.ilock=0;
superblock.fmod=0;
superblock.time[0]=currenttime->tm_hour;
superblock.time[1]=currenttime->tm_min;
/*Writing to Superblock*/
rvalue=lseek(fsfd, BLOCK_SIZE, SEEK_SET);
if ((write(fsfd, &superblock, sizeof(struct superblock)))!=sizeof(struct superblock))
	printf("ERROR:Superblock not written\n");

return 1;
}

int CreateRootDirectory(struct inode inode, unsigned long inodeblocks)
{
int i;
int rvalue;
char buffer[14];
char eofindicator[4]="EOF";
struct directoryentry rdirectoryentry;
time_t presenttime;
struct tm *currenttime;
presenttime=time(0);                               /*This gives current time in secs*/
currenttime=localtime(&presenttime);               /*This converts secs into hrs and mins and returns a pointer to a 'struct tm'*/

memset(&inode, 0, sizeof(struct inode));
inode.flags=19876*2;
inode.nlinks=0;
inode.uid=1;
inode.gid=1;
inode.size0=0;                           /*size0 and size1 gives the size of the file itself.*/
inode.size1=BLOCK_SIZE;
/*Each directory has only 1 block of memory (I mean 512 Bytes). Therfore only 32 entries in 1 directory.*/

inode.addr[0]=(2+inodeblocks)*BLOCK_SIZE;          /*First block after i-list is for the superblock.*/

inode.actime[0]=currenttime->tm_hour;
inode.actime[1]=currenttime->tm_min;
inode.modtime[0]=currenttime->tm_hour;
inode.modtime[1]=currenttime->tm_min;

/*As you are allocating 1 inode to the root directory. This is the first inode in the i-list blocks.*/
superblock.ninode--;        /*The number free inodes IN THE SUPERBLOCK is reduced by 1*/
numberofinodesrem--;        /*The number of inodes now is (inodeblocks*16)-1*/
numofdatablocksrem--;       /*Total # of data blocks remaining now.*/

/*Superblock modified; Hence update*/
rvalue=lseek(fsfd, BLOCK_SIZE, SEEK_SET);
if ((write(fsfd, &superblock, sizeof(struct superblock)))!=sizeof(struct superblock))
	{
		printf("ERROR:Superblock not written\n");
		exit(1);
	}

/*Write Inode info of the Root Directory.*/
rvalue=lseek(fsfd, ((BLOCK_SIZE*2)+(32*superblock.inode[iptr])), SEEK_SET); /*This location contains the info abt the root directory*/
iptr++;                                            /*Points to the next free inode in the superblock. As it is
																										inc by 1 the next free inode would be
																										superblock.inode[iptr]=(2*BLOCK_SIZE)+(32*iptr)*/

if ((write(fsfd, &inode, sizeof(struct inode)))!=sizeof(struct inode))
	{
		printf("ERROR:Root inode not written to the 1st block\n");
		exit(1);
	}

rvalue=lseek(fsfd, inode.addr[0], SEEK_SET);   /*Move to the first block right after the 'Inode List'*/
rdirectoryentry.inodenumber=0;

/*Now create directory entries '.'-current directory and '..'-parent directory*/

sprintf(buffer, ".");													
strcpy(rdirectoryentry.filename, buffer);
if ((write(fsfd, &rdirectoryentry.inodenumber, sizeof(unsigned short)))!=sizeof(unsigned short))
	{
		printf("ERROR:In Root Dir root inode number not written.\n");
		exit(1);
	}
if ((write(fsfd, rdirectoryentry.filename, sizeof(rdirectoryentry.filename)))!=sizeof(rdirectoryentry.filename)) 
	{
		printf("ERROR:Root filename not written.\n");
		exit(1);
	}
sprintf(buffer, "..");
strcpy(rdirectoryentry.filename, buffer);
if ((write(fsfd, &rdirectoryentry.inodenumber, sizeof(unsigned short)))!=sizeof(unsigned short))
	{
		printf("ERROR:In Root Dir parent inode number not written.\n");
		exit(1);
	}
if ((write(fsfd, rdirectoryentry.filename, sizeof(rdirectoryentry.filename)))!=sizeof(rdirectoryentry.filename)) 
	{
		printf("ERROR:Parent filename in Root Dir not written.\n");
		exit(1);
	}
if ((write(fsfd, eofindicator, 4))!=4)
	{
		printf("ERROR in initffs:EOF indicator not written.\n");
		exit(1);
	}
/*Updating the current working directory, current inode # and parent inode # of the cwd*/

strcpy(currentpath, "/");           /*Root Directory.*/
unsigned short cparentinode=0;
unsigned short cinode=0;

close(fsfd);
}
